package com.fulihui.wgj.service.material;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import com.fulihui.common.builder.rpc.RpcResultBuilder;
import com.fulihui.common.conv.BeanConv;
import com.fulihui.common.error.Errors;
import com.fulihui.common.error.InvokeServiceException;
import com.fulihui.common.result.rpc.BaseResult;
import com.fulihui.common.result.rpc.SimpleResult;
import com.fulihui.common.util.ConditionValidator;
import com.fulihui.common.util.PlatformUtil;
import com.fulihui.weixinsdk.WeixinSDK;
import com.fulihui.weixinsdk.model.Material;
import com.fulihui.weixinsdk.model.MaterialContent;
import com.fulihui.weixinsdk.model.MaterialItem;
import com.fulihui.weixinsdk.request.material.MaterialGetReuest;
import com.fulihui.weixinsdk.result.material.MaterialGetResult;
import com.fulihui.wgj.dal.mybatis.domain.WxMaterial;
import com.fulihui.wgj.dal.mybatis.repository.WxMaterialRepository;
import com.fulihui.wgj.facade.dto.WxMaterialDTO;
import com.fulihui.wgj.facade.request.material.WxMaterialPageQueryRequest;
import com.fulihui.wgj.facade.request.material.WxMaterialRequest;
import com.fulihui.wgj.facade.request.material.WxMaterialSyncRequest;
import com.fulihui.wgj.facade.result.material.WxMaterialPageResult;
import com.fulihui.wgj.facade.service.material.WxMaterialService;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 微信素材服务
 *
 * @author wang_wx
 * @date 2018-07-11
 */
@Component
@Service(interfaceClass = WxMaterialService.class, version = "1.0.0", timeout = 12000)
public class WxMaterialServiceImpl implements WxMaterialService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WxMaterialServiceImpl.class);

    /**
     * 分页的上限
     */
    private static final int PAGE_NO_UPPER_LIMIT = 1000;

    @Autowired
    PlatformUtil platformUtil;

    @Autowired
    WeixinSDK weixinSDK;

    @Autowired
    WxMaterialRepository wxMaterialRepository;

    @Override
    public BaseResult syncMaterial(WxMaterialSyncRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        String appId = request.getAppId();
        String type = request.getType();
        String token = platformUtil.get(appId);
        if (StringUtils.isBlank(token)) {
            LOGGER.warn("公众号token不存在");
            return RpcResultBuilder.fail(null);
        }
        List<Material> materials;
        try {
            materials = pageSyncMaterialBySDK(token, type);
        } catch (Exception e) {
            LOGGER.error("pageSyncMaterialBySDK error", e);
            return RpcResultBuilder.fail(null);
        }
        if (!CollectionUtils.isEmpty(materials)) {
            materials.forEach(material -> {
                WxMaterial wxMaterial = new WxMaterial();

                MaterialContent materialContent = material.getContent();
                if (Objects.nonNull(materialContent)) {
                    // 将图文消息content字段内容置空（content为图文内容，字段过长，无需存储）且有特殊符号
                    List<MaterialItem> newsItem = materialContent.getNews_item();
                    if (!CollectionUtils.isEmpty(newsItem)) {
                        newsItem.forEach(items -> items.setContent(""));
                    }
                    wxMaterial.setContent(escape(JSONObject.toJSONString(materialContent)));
                }

                wxMaterial.setMediaId(material.getMedia_id());
                wxMaterial.setContent(JSONObject.toJSONString(materialContent));
                wxMaterial.setAppId(appId);
                wxMaterial.setType(type);
                wxMaterial.setImageUrl(material.getUrl());
                wxMaterial.setUpdateTime(new Date(material.getUpdate_time() * 1000L));
                wxMaterial.setGmtModified(new Date());
                // 查询素材是否存在
                WxMaterial wxMaterialQuery = new WxMaterial();
                wxMaterialQuery.setMediaId(material.getMedia_id());
                WxMaterial exist = wxMaterialRepository.queryOne(wxMaterialQuery);
                if (Objects.isNull(exist)) {
                    wxMaterialRepository.saveSelective(wxMaterial);
                } else {
                    wxMaterialRepository.updateSelective(wxMaterial);
                }
            });
        }
        return RpcResultBuilder.succ();
    }

    /**
     * 转移特殊字符
     *
     * @param str
     * @return
     */
    private String escape(String str) {
        return str.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"");
    }

    /**
     * 分页拉取素材
     *
     * @param accessToken
     * @param materialType
     * @return
     */
    List<Material> pageSyncMaterialBySDK(String accessToken, String materialType) {
        List<Material> materials = Lists.newArrayList();

        MaterialGetReuest materialRequest = new MaterialGetReuest();
        materialRequest.setAccess_token(accessToken);
        materialRequest.setType(materialType);
        int offset = 0;
        int count = 100;
        for (int pageNo = 1; pageNo <= PAGE_NO_UPPER_LIMIT; pageNo++) {
            materialRequest.setOffset(offset);
            materialRequest.setCount(count);
            MaterialGetResult materialGetResult = weixinSDK.invokeService(materialRequest);
            if (!materialGetResult.isSuccess()) {
                LOGGER.error("pageSyncMaterialBySDK fail , materialGetResult=", materialGetResult);
            }
            List<Material> materialList = materialGetResult.getItem();
            if (!CollectionUtils.isEmpty(materialList)) {
                materials.addAll(materialList);
                //FIXME by wang_wx 因微信返回的total_count和item_count不准 不得作为分页的依据 故默认有下一页
                offset += offset + count;
            } else {
                // 分页无结果跳出循环
                break;
            }
        }
        return materials;
    }

    @Override
    public SimpleResult<List<WxMaterialDTO>> queryWxMaterialByType(WxMaterialSyncRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        Example example = new Example(WxMaterial.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appId", request.getAppId());
        criteria.andEqualTo("type", request.getType());
        example.orderBy("updateTime").desc();
        List<WxMaterial> wxMaterials = wxMaterialRepository.queryByExample(example);
        List<WxMaterialDTO> materialDTOS = null;
        if (!CollectionUtils.isEmpty(wxMaterials)) {
            materialDTOS = BeanConv.copy(wxMaterials, WxMaterialDTO.class);
        }
        return RpcResultBuilder.succSimple(materialDTOS);
    }

    @Override
    public WxMaterialPageResult pageQueryWxMaterialByType(WxMaterialPageQueryRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        Example example = new Example(WxMaterial.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appId", request.getAppId());
        criteria.andEqualTo("type", request.getType());
        example.orderBy("updateTime").desc();
        PageInfo<WxMaterial> pageInfo = wxMaterialRepository.queryPageListByExample(example, request.getPage(), request.getRows());
        long total = pageInfo.getTotal();
        WxMaterialPageResult wxMaterialPageResult = RpcResultBuilder.succPageResult(WxMaterialPageResult.class, pageInfo.getPageNum(), pageInfo.getPageSize(), Math.toIntExact(total));
        if (total > 0) {
            List<WxMaterialDTO> materialDTOS = BeanConv.copy(pageInfo.getList(), WxMaterialDTO.class);
            wxMaterialPageResult.setValue(materialDTOS);
        }
        LOGGER.info("rpc pageQueryWxMaterialByType end, result={}", wxMaterialPageResult);
        return wxMaterialPageResult;
    }

    @Override
    public SimpleResult<WxMaterialDTO> queryMaterialById(String mediaId) {
        WxMaterial wxMaterial = wxMaterialRepository.queryById(mediaId);
        WxMaterialDTO materialDTO = null;
        if (Objects.nonNull(wxMaterial)) {
            materialDTO = BeanConv.copy(wxMaterial, WxMaterialDTO.class);
        }
        return RpcResultBuilder.succSimple(materialDTO);
    }

    @Override
    public BaseResult saveWxMaterial(WxMaterialRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        WxMaterial material = BeanConv.copy(request, WxMaterial.class);
        WxMaterial exist = wxMaterialRepository.queryById(material.getMediaId());
        int count;
        if (Objects.isNull(exist)) {
            count = wxMaterialRepository.saveSelective(material);
        } else {
            material.setGmtModified(new Date());
            count = wxMaterialRepository.updateSelective(material);
        }
        return count > 0 ? RpcResultBuilder.succ() : RpcResultBuilder.fail(Errors.Commons.SAVE_FAILED);
    }
}
